package com.neusoft.neuiotms.dcom.service.change.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.neusoft.bizcore.activiti.dto.DataModelDTO;
import com.neusoft.bizcore.activiti.dto.PendingDataDTO;
import com.neusoft.bizcore.activiti.dto.ServiceDataModelDTO;
import com.neusoft.bizcore.activiti.enums.OperationTypeEnum;
import com.neusoft.bizcore.activiti.enums.PendingDataStatusEnum;
import com.neusoft.bizcore.activiti.service.LockDataService;
import com.neusoft.bizcore.activiti.service.PendingDataService;
import com.neusoft.bizcore.activiti.service.ProcessInstanceService;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.neuiotms.dcom.converter.change.ChangeCiPropertyDataConverter;
import com.neusoft.neuiotms.dcom.converter.change.ChangeCiRelationDataConverter;
import com.neusoft.neuiotms.dcom.converter.change.ChangeConfirmationConverter;
import com.neusoft.neuiotms.dcom.dto.change.ChangeCiPropertyDTO;
import com.neusoft.neuiotms.dcom.dto.change.ChangeCiPropertyDataDTO;
import com.neusoft.neuiotms.dcom.dto.change.ChangeCiRelationDTO;
import com.neusoft.neuiotms.dcom.dto.change.ChangeCiRelationDataDTO;
import com.neusoft.neuiotms.dcom.dto.change.ChangeConfirmationDTO;
import com.neusoft.neuiotms.dcom.dto.change.ChangeImplementationDTO;
import com.neusoft.neuiotms.dcom.dto.change.ChangeRegistrationDTO;
import com.neusoft.neuiotms.dcom.model.change.ChangeConfirmation;
import com.neusoft.neuiotms.dcom.model.enums.ChangeConfirmationOperationEnum;
import com.neusoft.neuiotms.dcom.repository.change.ChangeConfirmationRepository;
import com.neusoft.neuiotms.dcom.service.change.ChangeConfirmationService;
import com.neusoft.neuiotms.dcom.service.change.ChangeImplementationService;
import com.neusoft.neuiotms.dcom.service.change.ChangeRegistrationService;
import com.neusoft.neuiotms.micro.cmdb.CmdbMicroService;

@Service
public class ChangeConfirmationServiceImpl implements ChangeConfirmationService {

    @Autowired
    private ChangeConfirmationRepository changeConfirmationRepository;

    @Autowired
    private ChangeConfirmationConverter changeConfirmationConverter;

    @Autowired
    private ProcessInstanceService processInstanceService;

    @Autowired
    private ChangeCiRelationDataConverter changeCiRelationDataConverter;

    @Autowired
    private ChangeCiPropertyDataConverter changeCiPropertyDataConverter;

    @Autowired
    private PendingDataService pendingDataService;

    @Autowired
    private LockDataService lockDataService;

    @Autowired
    private CmdbMicroService cmdbMicroService;

    @Autowired
    private ChangeImplementationService changeImplementationService;

    @Autowired
    private ChangeRegistrationService changeRegistrationService;

    @Override
    @Transactional
    public ChangeConfirmationDTO create(final ChangeConfirmationDTO dto, final UserBean user) {
        // 设置流程变量
        this.processInstanceService.setGlobalVariable(dto.getTaskId(), "changeConfirmationOperation",
                dto.getOperation());

        // 通过
        if (ChangeConfirmationOperationEnum.pass.name().equals(dto.getOperation().name())) {
            // 将变更实施的最新数据（包括配置项属性与配置项关系）获取到并放到业务中间表，待变更结束时统一更新。

            final List<ServiceDataModelDTO> listServiceDataModelDTO = new ArrayList<>();

            // 待更新配置项属性数据
            listServiceDataModelDTO.addAll(this.processCiPropertyPendingData(dto.getWorkOrderNum()));

            // 待更新配置项关系数据
            listServiceDataModelDTO.addAll(this.processCiRelationPendingData(dto.getWorkOrderNum()));

            if (CollectionUtils.isNotEmpty(listServiceDataModelDTO)) {
                this.pendingDataService.save(this.getClass().getName(), "dealChangeData", dto.getWorkOrderNum(),
                        dto.getTaskId(), listServiceDataModelDTO);
            } else {
                // 解锁数据
                this.lockDataService.deleteByWorkNum(dto.getWorkOrderNum());
            }
        }
        // 转服务台
        if (ChangeConfirmationOperationEnum.serviceDesk.name().equals(dto.getOperation().name())) {
            // 解锁数据
            this.lockDataService.deleteByWorkNum(dto.getWorkOrderNum());
        }
        // 驳回时无需特别处理

        // 查询当前workNum和TaskId下是否存在记录
        final ChangeConfirmation oldModel = this.changeConfirmationRepository.findByWorkOrderNumAndTaskId(
                dto.getWorkOrderNum(), dto.getTaskId());
        if (oldModel == null) { // 如果不存在新增
            dto.setId(null);
        }

        final ChangeConfirmation model = this.changeConfirmationConverter.toModel(dto);
        this.changeConfirmationRepository.save(model);

        // 完成节点
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);

        return this.changeConfirmationConverter.toDTO(model);
    }

    @Override
    public ChangeConfirmationDTO detail(final String workOrderNum, final String taskId, final UserBean user) {
        ChangeConfirmation model = null;
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.changeConfirmationRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (lastTaskId == null) {
                        return new ChangeConfirmationDTO();
                    } else {
                        model = this.changeConfirmationRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                                lastTaskId);
                    }
                }
            } else if ("NULL".equals(taskId)) {
                model = this.changeConfirmationRepository.findByWorkOrderNum(workOrderNum);
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        return this.changeConfirmationConverter.toDTO(model);
    }

    @Override
    public ChangeConfirmationDTO findByWorkOrderNumAndTaskId(final String workOrderNum, final String taskId) {
        final ChangeConfirmation model =
                this.changeConfirmationRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
        return this.changeConfirmationConverter.toDTO(model);
    }

    @Override
    public void deleteByWorkOrderNum(final String workOrderNum) {
        this.changeConfirmationRepository.deleteByWorkOrderNum(workOrderNum);
    }

    /**
     * 处理待更新配置项属性数据为业务中间表需要的格式
     *
     * @param workOrderNum
     * @return
     */
    private List<ServiceDataModelDTO> processCiPropertyPendingData(final String workOrderNum) {
        final List<ServiceDataModelDTO> listServiceDataModelDTO = new ArrayList<>();

        final ChangeImplementationDTO changeImplementationDTO =
                this.changeImplementationService.findByWorkNum(workOrderNum);

        final List<ChangeCiPropertyDTO> listCiPropertyDTO = changeImplementationDTO.getChangeCiPropertyList();
        if (CollectionUtils.isNotEmpty(listCiPropertyDTO)) {
            listCiPropertyDTO.stream().forEach(item -> {
                final List<ChangeCiPropertyDataDTO> temp = new ArrayList<>();
                final ChangeCiPropertyDataDTO dataDTO = new ChangeCiPropertyDataDTO();

                final JSONObject param = new JSONObject();
                param.put("value", item.getAfterChange());
                dataDTO.setValue(param);
                dataDTO.setAttr(item.getKey());
                temp.add(dataDTO);

                listServiceDataModelDTO
                        .addAll(this.changeCiPropertyDataConverter.converter(temp, "property",
                                OperationTypeEnum.update));

            });
        }
        return listServiceDataModelDTO;
    }

    /**
     * 处理待更新配置项关系数据为业务中间表需要的格式
     *
     * @param workOrderNum
     * @return
     */
    private List<ServiceDataModelDTO> processCiRelationPendingData(final String workOrderNum) {

        final List<ServiceDataModelDTO> listServiceDataModelDTO = new ArrayList<>();

        final ChangeImplementationDTO changeImplementationDTO =
                this.changeImplementationService.findByWorkNum(workOrderNum);

        final List<ChangeCiRelationDTO> listCiRelationDTO = changeImplementationDTO.getChangeCiRelationList();
        if (CollectionUtils.isNotEmpty(listCiRelationDTO)) {

            listCiRelationDTO.stream().forEach(item -> {
                // 转换成 ChangeCiRelationDataDTO
                final List<ChangeCiRelationDataDTO> temp = new ArrayList<>();
                final ChangeCiRelationDataDTO dataDTO = new ChangeCiRelationDataDTO();

                // 已有关系编辑时，需要注意放变更后的属性
                if (!item.getAddFlag() && !item.getDeleteFlag()) {
                    dataDTO.setAttrs(item.getAttrsChange());
                    dataDTO.setDesc(item.getDescChange());
                } else {
                    dataDTO.setAttrs(item.getAttrs());
                    dataDTO.setDesc(item.getDesc());
                }
                dataDTO.setDest(item.getDest());
                dataDTO.setId(item.getRelationId());
                dataDTO.setRela(item.getRela());
                dataDTO.setSrc(item.getSrc());
                temp.add(dataDTO);

                // 新增的关系直接保存
                if (item.getAddFlag()) {
                    listServiceDataModelDTO
                            .addAll(this.changeCiRelationDataConverter.converter(temp, "relation",
                                    OperationTypeEnum.add));
                }
                // 已有关系有删除标记，直接删除
                if (!item.getAddFlag() && item.getDeleteFlag()) {
                    listServiceDataModelDTO
                            .addAll(this.changeCiRelationDataConverter.converter(temp, "relation",
                                    OperationTypeEnum.delete));
                }
                // 已有关系无删除标记，更新数据
                if (!item.getAddFlag() && !item.getDeleteFlag()) {
                    listServiceDataModelDTO
                            .addAll(this.changeCiRelationDataConverter.converter(temp, "relation",
                                    OperationTypeEnum.update));
                }

            });
        }
        return listServiceDataModelDTO;
    }

    /**
     * 往CMDB更新配置项属性与关系数据，本方法在变更工单结束后调用
     */
    @Override
    @Transactional
    public Object dealChangeData(final PendingDataDTO pd) {
        try {
            final ChangeRegistrationDTO changeRegistrationDTO =
                    this.changeRegistrationService.findByWorkNum(pd.getWorkNum());
            final String ciId = changeRegistrationDTO.getCiId();

            final List<ServiceDataModelDTO> listServiceDataModelDTO = pd.getData();
            listServiceDataModelDTO.stream().forEach(item -> {
                final DataModelDTO dataModelDTO = item.getData();
                final JSONObject dataDTO = JSON.parseObject(dataModelDTO.getJsonData());
                final OperationTypeEnum type = dataModelDTO.getType();
                // 关系
                if ("relation".equals(item.getServiceName())) {
                    // add
                    if (type.getValue() == 1) {
                        this.cmdbMicroService.addRelation(ciId, dataDTO.toJSONString());
                    }
                    // update
                    if (type.getValue() == 2) {
                        this.cmdbMicroService.updateRelation(dataDTO.getString("id"),
                                dataDTO.toJSONString());
                    }
                    // delete
                    if (type.getValue() == 3) {
                        this.cmdbMicroService.deleteRelation(ciId, dataDTO.getString("id"));
                    }
                }
                // 属性，属性只涉及到更新操作
                if ("property".equals(item.getServiceName())) {
                    this.cmdbMicroService.updateAttr(ciId, dataDTO.getString("attr"), dataDTO.getString("value"));
                }
            });

            // 解锁配置项
            this.lockDataService.deleteByWorkNum(pd.getWorkNum());
            // 处理成功后删除中间业务表保存的数据
            this.pendingDataService.delete(pd.getId());
        } catch (final Exception e) {
            this.pendingDataService.updateStatus(pd.getId(), PendingDataStatusEnum.dealError);
            e.printStackTrace();
            return "FAILURE";
        }
        return "SUCCESS";
    }

}
